package jvs.vfs.opt;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;

import jvs.vfs.IFile;
import jvs.vfs.IFileBaseImpl;
import android.content.Context;
import android.util.Log;

/**
 * @author qiangli
 * 
 */

public abstract class ItemListFileImpl extends IFileBaseImpl {

	private static Object lock = new Object();

	private static final String LOG_TAG = "ItemListFileImpl";

	private static String[] toArray(ItemInfo[] list) {
		if (list == null) {
			return null;
		}
		int sz = list.length;
		String[] sa = new String[sz];
		for (int i = 0; i < sz; i++) {
			ItemInfo ai = list[i];
			sa[i] = ai.id;
		}
		return sa;
	}
	
	protected int index;
	
	protected ItemInfo info;

	protected boolean isFolder;

	protected String path;

	/**
	 * @param uri
	 */
	public ItemListFileImpl(URI uri) {
		super(uri);
		if (DEBUG) {
			Log.d(LOG_TAG, "ItemListFileImpl " + uri);
		}
		//
		String p = path(uri);
		path = p;
		isFolder = true;
		//
		if (isTop()) {
			return;
		}
		//
		int idx = matchFolder(p);
		if (idx != -1) {
			// folder list
			index = idx;
			return;
		}
		//
		isFolder = false;
		idx = matchItem(p);
		if (idx == -1) {
			throw new IllegalArgumentException("invalid uri: " + uri);
		}
		index = idx;
		info = findItem(idx, p);
	}

	protected ItemListFileImpl(URI uri, ItemInfo info) {
		super(uri);
		this.info = info;
		//
		this.isFolder = false;
		this.index = -1;
		this.path = null;
		if (DEBUG) {
			Log.d(LOG_TAG, "ItemListFileImpl " + uri + " " + info);
		}
	}

	@Override
	public boolean canExecute() {
		return (info != null);
	}

	@Override
	public boolean canRead() {
		return true;
	}

	@Override
	public boolean canWrite() {
		return false;
	}

	@Override
	public boolean create() {
		return false;
	}

	@Override
	public boolean delete() {
		return false;
	}

	@Override
	public boolean execute() {
		if (info == null || info.intent == null) {
			return false;
		}
		try {
			Context ctx = (Context) fs.getContext();
			if (info.intent == null) {
				return false;
			}
			ctx.startActivity(info.intent);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	@Override
	public boolean exists() {
		return true;
	}

	protected ItemInfo findItem(int index, String p) {
		if (DEBUG) {
			Log.d(LOG_TAG, "findItem index: " + index + " path: " + p);
		}
		//
		ItemInfo[] list = load(p, index);
		if (list != null) {
			String n = name(p);
			for (ItemInfo i : list) {
				if (i.id.equals(n)) {
					if (DEBUG) {
						Log.d(LOG_TAG, "findItem found: " + i);
					}
					return i;
				}
			}
		}
		return null;
	}

	/**
	 * 
	 * @return total count of top level folders
	 */
//	protected int getCount() {
//		String[] fl = getFolders();
//		return fl.length;
//	}

	@Override
	public String getDisplayName() {
		if (info != null) {
			return info.title;
		}
		return super.getDisplayName();
	}

	/**
	 * 
	 * @return array of names for top level folders
	 */
	protected abstract String[] getFolders();

	@Override
	public Object getIcon() {
		if (info != null) {
			return info.icon;
		}
		return super.getIcon();
	}

	@Override
	public InputStream getInputStream() {
		return null;
	}

	@Override
	public long getLastModified() {
		return 0;
	}

	@Override
	public long getLength() {
		return 0;
	}

	@Override
	public String getName() {
		if (info != null) {
			return info.id;
		}
		return super.getName();
	}

	@Override
	public OutputStream getOutputStream() {
		return null;
	}

	@Override
	public String getPhoneticName() {
		if (info != null) {
			return info.title;
		}
		return super.getPhoneticName();
	}

	@Override
	public String getSortKey() {
		if (info != null) {
			return info.sortkey;
		}
		return super.getSortKey();
	}

	@Override
	public boolean isDirectory() {
		return (isFolder);
	}

	@Override
	public boolean isEmpty() {
		String p = path;
		if (p.equals("/")) {
			return false;
		}
		int i = index; //matchFolder(p);
		if (i != -1) {
			ItemInfo[] l = load(p, i);
			return (l != null && l.length > 0);
		}
		return true;
	}

	@Override
	public boolean isFile() {
		return (!isFolder);
	}

	@Override
	public boolean isLocal() {
		return true;
	}

	@Override
	public boolean isNative() {
		return false;
	}

	protected boolean isTop() {
		return (path.equals("/"));
	}

	@Override
	public String[] list() {
		if (!isFolder) {
			return null;
		}
		String p = path(uri);
		if (p.equals("/")) {
			return getFolders();
		}
		int idx =  index; //matchFolder(p);
//		if (idx != -1 && lists != null) {
//			return toArray(lists[idx]);
//		}
		if (idx != -1) {
			ItemInfo[] list = load(p, idx);
			if (list == null) {
				return null;
			}
			return toArray(list);
		}
		return null;
	}

	@Override
	public IFile[] listFiles() {
		if (!isFolder) {
			return null;
		}
		String p = path(uri);
		if (p.equals("/")) {
			return super.listFiles();
		}
		int idx = index; //matchFolder(p);
		ItemInfo[] al = null;
		//load(p);
		if (idx != -1) {
			al = load(p, idx);
		}
//		if (idx != -1 && lists != null) {
//			al = lists[idx];
//		}
		if (al == null) {
			return null;
		}
		int len = al.length;
		IFile[] rl = new IFile[len];
		for (int i = 0; i < len; i++) {
			ItemInfo ai = al[i];
			URI pu = uri.resolve(uri.getPath() + "/" + ai.id);
			rl[i] = newInstance(pu, ai);
		}
		return rl;
	}

	/**
	 * 
	 * @param ctx
	 *            Context
	 * @param idx
	 *            index
	 * @return list of items the folder of the specified index
	 */
	protected abstract ItemInfo[] load(Context ctx, int idx);

	private ItemInfo[] load(String p, int i) {
		if (i == -1) {
			return null;
		}
		final ItemInfo[][] lists = lists();
		if (lists == null) {
			return null;
		}
		synchronized (lock) {
			try {
				if (DEBUG) {
					Log.d(LOG_TAG, "load " + p +" lists: " + lists.length +" index: " + i);
				}
				//
				ItemInfo[] list = lists[i];
				if (list != null) {
					return list;
				}
				Context ctx = (Context) fs.getContext();
				list = load(ctx, i);
				lists[i] = list;
				
				if (DEBUG) {
					Log.d(LOG_TAG, "ItemListFileImpl loaded [" + i + "] "
							+ list);
				}
				return list;
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}
	}

	protected abstract ItemInfo[][] lists();

	protected int matchFolder(String s) {
		String[] fl = getFolders();
		int len = fl.length;
		for (int i = 0; i < len; i++) {
			if (fl[i].equals(s)) {
				return i;
			}
		}
		return -1;
	}

	protected int matchItem(String s) {
		String[] fl = getFolders();
		int len = fl.length;
		for (int i = 0; i < len; i++) {
			if (s.startsWith(fl[i])) {
				return i;
			}
		}
		return -1;
	}

	@Override
	public boolean mkdir() {
		return false;
	}

	@Override
	public boolean move(URI uri) {
		return false;
	}

	protected abstract IFile newInstance(URI pu, ItemInfo ai);

	@Override
	public void refresh() {
		ItemInfo[][] l = lists();
		if (l == null) {
			return;
		}
		synchronized(lock) {
			for (int i = 0; i < l.length; i++) {
				l[i] = null;
			}
		}
	}
}
